﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Web;
using System.Web.Hosting;
using System.Web.Security;
using EPiServer;
using EPiServer.Core;
using EPiServer.Core.Html;
using EPiServer.DataAccess;
using EPiServer.Security;
using EPiServer.Web;
using EPiServer.Web.Hosting;
using EPiServer.XmlRpc;
using PageTypeBuilder;
using TemplateFoundation.Configuration;
using TemplateFoundation.Core;
using TemplateFoundation.Exceptions;
using TemplateFoundation.PageTypes;
using TemplateFoundation.Tags;

namespace TemplateFoundation.MetaWeblog
{
    /// <summary>
    /// Handles XML RPC calls for the MetaWeblog API
    /// </summary>
    [XmlRpcService(Description="MetaWeblog support for EPiServer CMS provided by EPiServer Template Foundation", Name="MetaWeblog for EPiServer CMS")]
    public class MetaWeblogHandler : XmlRpcService
    {
        /// <summary>
        /// Deletes a page
        /// </summary>
        /// <param name="blogId">Page ID of the articles container</param>
        /// <param name="username">A valid EPiServer username</param>
        /// <param name="password">Password for the EPiServer user</param>
        /// <param name="page_id">PageLink ID of the page</param>
        /// <returns></returns>
        [XmlRpcMethod("wp.deletePage")]
        public virtual bool DeletePage(string blogId, string username, string password, string page_id)
        {
            try
            {
                Impersonate(username, password);

                ValidateBlogId(blogId);

                DataFactory.Instance.MoveToWastebasket(new PageReference(int.Parse(page_id)));

                return true;
            }
            catch (Exception exception)
            {
                throw new XmlRpcFaultException(100, "Failed on delete page " + page_id + "\r\n" + exception.Message);
            }
        }

        /// <summary>
        /// Deletes the post.
        /// </summary>
        /// <param name="appKey">The app key.</param>
        /// <param name="postId">PageLink ID of the post</param>
        /// <param name="username">A valid EPiServer username</param>
        /// <param name="password">Password for the EPiServer user</param>
        /// <param name="publish">Whether to publish the page or post, or if it should simply be saved</param>
        /// <returns></returns>
        [XmlRpcMethod("blogger.deletePost")]
        public virtual bool DeletePost(string appKey, string postId, string username, string password, bool publish)
        {
            this.Impersonate(username, password);

            try
            {
                Impersonate(username, password);

                DataFactory.Instance.MoveToWastebasket(new PageReference(int.Parse(postId)));
            }
            catch (Exception exception)
            {
                throw new XmlRpcFaultException(100, "Failed on delete post " + postId + "\r\n" + exception.Message);
            }
            return true;
        }

        /// <summary>
        /// Edits an existing page
        /// </summary>
        /// <param name="blogId">Page ID of the articles container</param>
        /// <param name="pageId">PageLink ID of the page</param>
        /// <param name="username">A valid EPiServer username</param>
        /// <param name="password">Password for the EPiServer user</param>
        /// <param name="content">Main body content for a page or post</param>
        /// <param name="publish">Whether to publish the page or post, or if it should simply be saved</param>
        /// <returns></returns>
        [XmlRpcMethod("wp.editPage")]
        public virtual string EditPage(string blogId, string pageId, string username, string password, PageObjectData content, bool publish)
        {
            ValidateBlogId(blogId);

            Impersonate(username, password);
           
            try
            {
                var page = DataFactory.Instance.GetPage(new PageReference(int.Parse(pageId))).CreateWritableClone() as IStandardPage;

                if (page==null)
                {
                    throw new TemplateFoundationException("The specified post ID did not map to a valid standard page");
                }

                if (!string.IsNullOrEmpty(content.wp_author_id))
                {
                    // Verify a page type for contact persons has been specified
                    if (Settings.Instance.PersonPageTypeId.HasValue)
                    {
                        // Find contact person's page and set the ContactPerson property accordingly
                        var authors = PageFactory.Instance.GetPagesByType(Settings.Instance.PersonPageTypeId.Value, false);

                        var authorPageLink = PageReference.EmptyReference;

                        var authorId = int.Parse(content.wp_author_id);

                        foreach (var p in authors)
                        {
                            if (p.PageLink.ID == authorId)
                            {
                                authorPageLink = p.PageLink;
                                break;
                            }
                        }

                        page.PageContact = authorPageLink;
                    }
                    else
                    {
                        page.PageContact = PageReference.EmptyReference;
                    }
                }
                else
                {
                    page.PageContact = PageReference.EmptyReference;
                }

                page.PageName = HttpUtility.HtmlDecode(content.title);
                page.MainBody = content.description;
                page.Keywords = content.mt_keywords;
                page.URLSegment = HttpUtility.UrlEncode(content.wp_slug);

                if (page is IEnableComments)
                {
                    ((IEnableComments)page).EnableComments = content.mt_allow_comments == 1;
                }

                if (content.dateCreated>new DateTime(1753, 1, 1))
                {
                    page.StartPublish = content.dateCreated;
                }

                if (string.IsNullOrEmpty(content.mt_excerpt))
                {
                    page.Description = TextIndexer.StripHtml(content.description, 160);
                }
                else
                {
                    page.Description = content.mt_excerpt;
                }

                page.Tags.Clear();

                if (content.categories!=null)
                {
                    foreach (string tag in content.categories)
                    {
                        page.Tags.Add(new Tag(tag));
                    }
                }

                DataFactory.Instance.Save((PageData)page, publish ? SaveAction.Publish : SaveAction.Save);

                return page.PageLink.ID.ToString();
            }
            catch (Exception exception)
            {
                throw new XmlRpcFaultException(400, "Fail on edit post " + pageId + "\r\n" + exception.Message);
            }
        }

        /// <summary>
        /// Edits the post.
        /// </summary>
        /// <param name="postId">PageLink ID of the post</param>
        /// <param name="username">A valid EPiServer username</param>
        /// <param name="password">Password for the EPiServer user</param>
        /// <param name="content">Main body content for a page or post</param>
        /// <param name="publish">Whether to publish the page or post, or if it should simply be saved</param>
        /// <returns></returns>
        [XmlRpcMethod("metaWeblog.editPost")]
        public bool EditPost(string postId, string username, string password, ContentData content, bool publish)
        {
            Impersonate(username, password);

            try
            {
                var post = DataFactory.Instance.GetPage(new PageReference(int.Parse(postId))).CreateWritableClone() as ArticlePageBase;

                if (post==null)
                {
                    throw new TemplateFoundationException("The specified post ID did not map to a valid article page");
                }

                if (!string.IsNullOrEmpty(content.wp_author_id))
                {
                    // Verify a page type for contact persons has been specified
                    if (Settings.Instance.PersonPageTypeId.HasValue)
                    {
                        // Find contact person's page and set the ContactPerson property accordingly
                        var authors = PageFactory.Instance.GetPagesByType(Settings.Instance.PersonPageTypeId.Value, false);

                        var authorPageLink = PageReference.EmptyReference;

                        var authorId = int.Parse(content.wp_author_id);

                        foreach (var p in authors)
                        {
                            if (p.PageLink.ID == authorId)
                            {
                                authorPageLink = p.PageLink;
                                break;
                            }
                        }

                        post.PageContact = authorPageLink;
                    }
                    else
                    {
                        post.PageContact = PageReference.EmptyReference;
                    }
                }
                else
                {
                    post.PageContact = PageReference.EmptyReference;
                }

                post.PageName = HttpUtility.HtmlDecode(content.title);
                post.Description = content.mt_excerpt;
                post.MainBody = content.description;
                post.Keywords = content.mt_keywords;
                post.EnableComments = content.mt_allow_comments == 1;
                post.URLSegment = HttpUtility.UrlEncode(content.wp_slug);

                if (content.dateCreated>new DateTime(1753, 1, 1))
                {
                    post.StartPublish = content.dateCreated;
                }

                // Add tags
                var tags = new TagCollection();
                foreach (string tag in content.categories)
                {
                    tags.Add(new Tag(tag));
                }
                post.Tags = tags;

                DataFactory.Instance.Save(post, publish ? SaveAction.Publish : SaveAction.Save);
            }
            catch (Exception ex)
            {
                throw new XmlRpcFaultException(400, "Fail on edit post " + postId + "\r\n" + ex.Message);
            }
            return true;
        }

        /// <summary>
        /// Gets the categories.
        /// </summary>
        /// <param name="blogId">Page ID of the articles container</param>
        /// <param name="username">A valid EPiServer username</param>
        /// <param name="password">Password for the EPiServer user</param>
        /// <returns></returns>
        [XmlRpcMethod("metaWeblog.getCategories")]
        public virtual CategoryData[] GetCategories(string blogId, string username, string password)
        {
            try
            {
                var tags = new List<CategoryData>();

                foreach (var tag in TagFactory.Instance.GetTags())
                {
                    tags.Add(new CategoryData()
                                 {
                                     categoryId = tag.ID.ToString(),
                                     categoryName = tag.Name,
                                     description = tag.Description,
                                     htmlUrl = tag.PageLink.GetPage().GetFriendlyUrl(true),
                                     name=tag.Name,
                                     slug = tag.UrlSegment,
                                     title = tag.Name
                                 });
                }

                return tags.ToArray();
            }
            catch
            {
                throw new XmlRpcFaultException(400, "Unable to retrieve tags");
            }
        }

        /// <summary>
        /// Gets the page list.
        /// </summary>
        /// <param name="blogId">Page ID of the articles container</param>
        /// <param name="username">A valid EPiServer username</param>
        /// <param name="password">Password for the EPiServer user</param>
        /// <returns></returns>
        [XmlRpcMethod("wp.getPageList")]
        public virtual PageObjectData[] GetPageList(string blogId, string username, string password)
        {
            try
            {
                var standardPages = PageFactory.Instance.GetStandardPages(0, false).Cast<StandardPageBase>();

                var pages = new List<PageObjectData>();

                // Get list of pages (excludes main body content)
                foreach (var page in standardPages)
                {
                    var slimPage = GetPage(blogId, page.PageLink.ID.ToString(), username, password);

                    // To reduce bandwidth use we'll strip the main content from pages for page lists
                    slimPage.text_more = string.Empty;
                    slimPage.description = string.Empty;

                    // Set the link to the internal URL so that editors don't accidentally link to friendly URLs in content
                    slimPage.link = page.LinkURL;
                    
                    pages.Add(slimPage);
                }

                return pages.ToArray();
            }
            catch
            {
                throw new XmlRpcFaultException(400, "Unable to retrieve list of standard pages");
            }
        }

        /// <summary>
        /// Gets the pages.
        /// </summary>
        /// <param name="blogId">Page ID of the articles container</param>
        /// <param name="username">A valid EPiServer username</param>
        /// <param name="password">Password for the EPiServer user</param>
        /// <param name="numberofpages">The numberofpages.</param>
        /// <returns></returns>
        [XmlRpcMethod("wp.getPages")]
        public virtual PageObjectData[] GetPages(string blogId, string username, string password, int numberofpages)
        {
            try
            {
                var standardPages = PageFactory.Instance.GetStandardPages(0, false);

                var pages = new List<PageObjectData>();

                // Return all pages
                foreach (var page in standardPages)
                {
                    pages.Add(GetPage(blogId,page.PageLink.ID.ToString(),username,password));
                }

                return pages.ToArray();
            }
            catch
            {
                throw new XmlRpcFaultException(400, "Unable to retrieve list of standard pages");
            }
        }

        /// <summary>
        /// Gets the post.
        /// </summary>
        /// <param name="postId">PageLink ID of the post</param>
        /// <param name="username">A valid EPiServer username</param>
        /// <param name="password">Password for the EPiServer user</param>
        /// <returns></returns>
        [XmlRpcMethod("metaWeblog.getPost")]
        public ContentData GetPost(string postId, string username, string password)
        {
            Impersonate(username, password);

            try
            {
                var page = DataFactory.Instance.GetPage(new PageReference(int.Parse(postId), true)) as ArticlePageBase;

                if (page==null)
                {
                    throw new TemplateFoundationException("Post ID did not map to a valid article page");
                }

                return new ContentData
                                  {
                                      categories = page.Tags.ToStringArray(),
                                      dateCreated = page.StartPublish,
                                      description = page.MainBody,
                                      link = page.GetFriendlyUrl(true),
                                      postid = page.PageLink.ID.ToString(),
                                      mt_keywords = page.Keywords,
                                      title = page.PageName,
                                      wp_slug = page.URLSegment,
                                      mt_excerpt = page.Description,
                                      wp_author = page.CreatedBy,
                                      wp_author_display_name = page.CreatedBy,
                                      wp_author_id = page.PageContact!=null ? page.PageContact.ID.ToString() : string.Empty
                                  };
            }
            catch
            {
                throw new XmlRpcFaultException(400, "Unable to retrieve page list");
            }
        }

        /// <summary>
        /// Gets the page.
        /// </summary>
        /// <param name="blogId">Page ID of the articles container</param>
        /// <param name="pageId">PageLink ID of the page</param>
        /// <param name="username">A valid EPiServer username</param>
        /// <param name="password">Password for the EPiServer user</param>
        /// <returns></returns>
        [XmlRpcMethod("wp.getPage")]
        public PageObjectData GetPage(string blogId, string pageId, string username, string password)
        {
            Impersonate(username, password);

            ValidateBlogId(blogId);

            try
            {
                var page = DataFactory.Instance.GetPage(new PageReference(int.Parse(pageId), true)) as StandardPageBase;

                if (page==null)
                {
                    throw new TemplateFoundationException("Page ID did not map to a valid page");
                }

                return new PageObjectData()
                {
                    categories = page.Tags==null ? new string[0] : page.Tags.ToStringArray(),
                    dateCreated = page.StartPublish,
                    description = page.MainBody,
                    link = page.GetFriendlyUrl(true),
                    postid = page.PageLink.ID.ToString(),
                    title = page.PageName,
                    page_id = page.PageLink.ID,
                    page_parent_id = page.ParentLink.ID,
                    wp_slug = page.URLSegment,
                    mt_excerpt = page.Description ?? string.Empty,
                    mt_keywords = page.Keywords ?? string.Empty,
                    page_title = page.Title ?? page.PageName,
                    permaLink = PermanentLinkUtility.GetPermanentLinkUrl(page.PageGuid,string.Empty).ToString(),
                    page_status = page.Status.ToString(),
                    wp_page_order = (int)page["PagePeerOrder"],
                    wp_page_parent_id = page.ParentLink.ID,
                    wp_page_parent_title = DataFactory.Instance.GetPage(page.ParentLink).PageName,
                    wp_author = page.CreatedBy,
                    wp_author_display_name = page.CreatedBy,
                    wp_author_id = page.PageContact!=null ? page.PageContact.ID.ToString() : string.Empty,
                    wp_password = string.Empty
                };
            }
            catch
            {
                throw new XmlRpcFaultException(400, "Unable to retrieve page");
            }
        }

        /// <summary>
        /// Gets the recent posts.
        /// </summary>
        /// <param name="blogId">Page ID of the articles container</param>
        /// <param name="username">A valid EPiServer username</param>
        /// <param name="password">Password for the EPiServer user</param>
        /// <param name="numberOfPost">The number of post.</param>
        /// <returns></returns>
        [XmlRpcMethod("metaWeblog.getRecentPosts")]
        public virtual ContentData[] GetRecentPosts(string blogId, string username, string password, int numberOfPost)
        {
            try
            {
                Impersonate(username, password);

                ValidateBlogId(blogId);

                var content = new List<ContentData>();

                foreach (var page in PageFactory.Instance.GetArticles(numberOfPost, MasterLanguageBranch, true).Cast<ArticlePageBase>())
                {
                    content.Add(new ContentData()
                                          {
                                              dateCreated = page.StartPublish,
                                              mt_excerpt = page.Description,
                                              link = page.LinkURL, // We use the internal URL so that editors don't accidentally insert links using the friendly URL
                                              postid = page.PageLink.ID.ToString(),
                                              title = page.PageName,
                                              categories = page.Tags.ToStringArray(),
                                              wp_author_id = page.PageContact!=null ? page.PageContact.ID.ToString() : string.Empty
                                          });
                }

                return content.ToArray();
            }
            catch (Exception ex)
            {
                throw new XmlRpcFaultException(400, "Unable to retrieve recent posts: " + ex.Message);
            }
        }

        /// <summary>
        /// Gets the users blogs.
        /// </summary>
        /// <param name="appKey">The app key.</param>
        /// <param name="username">A valid EPiServer username</param>
        /// <param name="password">Password for the EPiServer user</param>
        /// <returns></returns>
        [XmlRpcMethod("blogger.getUsersBlogs")]
        public virtual UserBlogData[] GetUsersBlogs(string appKey, string username, string password)
        {
            try
            {
                Impersonate(username, password);

                var blog = new UserBlogData()
                               {
                                   blogid = Settings.Instance.NewsContainer.ID.ToString(),
                                   blogName = Settings.Instance.NewsContainer.GetPage().PageName,
                                   url = Settings.Instance.NewsContainer.GetPage().LinkURL
                               };

                return new[] { blog };
            }
            catch
            {
                throw new XmlRpcFaultException(400, "Unable to retrieve blog information");
            }
        }

        /// <summary>
        /// Impersonates without requiring password validation
        /// </summary>
        /// <param name="username"></param>
        protected void Impersonate(string username)
        {
            PrincipalInfo.CurrentPrincipal = PrincipalInfo.CreatePrincipal(username);
        }

        /// <summary>
        /// Impersonates the specified username.
        /// </summary>
        /// <param name="username">A valid EPiServer username</param>
        /// <param name="password">Password for the EPiServer user</param>
        protected void Impersonate(string username, string password)
        {
            try
            {
                if (!Membership.Provider.ValidateUser(username, password))
                {
                    throw new XmlRpcFaultException(400, "Fail on validate user " + username);
                }
                PrincipalInfo.CurrentPrincipal = PrincipalInfo.CreatePrincipal(username);
            }
            catch (Exception exception)
            {
                throw new XmlRpcFaultException(400, string.Concat(new object[] { "Fail on impersonate for user ", username, "\r\n", exception }));
            }
        }

        /// <summary>
        /// News the category.
        /// </summary>
        /// <param name="blogId">Page ID of the articles container</param>
        /// <param name="username">A valid EPiServer username</param>
        /// <param name="password">Password for the EPiServer user</param>
        /// <param name="category">The category.</param>
        /// <returns></returns>
        [XmlRpcMethod("wp.newCategory")]
        public virtual string newCategory(string blogId, string username, string password, CategoryData category)
        {
            // TODO Create new category (note that new categories are still created when included in content data upon publishing/saving)
            throw new XmlRpcException("Not supported, categories are created when included in content data");
        }

        /// <summary>
        /// Returns a list of all authors, ie all contact pages on the site
        /// </summary>
        /// <param name="blogId"></param>
        /// <returns></returns>
        protected virtual AuthorData[] GetAuthors(int blogId)
        {
            ValidateBlogId(blogId.ToString());

            // Verify a page type for contact persons has been specified
            if(!Settings.Instance.PersonPageTypeId.HasValue)
            {
                return new AuthorData[0];
            }

            var authors = new List<AuthorData>();

            foreach (var page in PageFactory.Instance.GetPersons(false).OfType<PersonPageBase>())
            {
                var author = new AuthorData
                {
                    user_email = page.EmailAddress ?? string.Empty,
                    user_login = page.Name,
                    display_name = page.PageName,
                    user_id = page.PageLink.ID,
                    meta_value = page.Description ?? string.Empty
                };

                if(!authors.Contains(author))
                {
                    authors.Add(author);
                }
            }

            return authors.ToArray();
        }

        /// <summary>
        /// Gets the authors.
        /// </summary>
        /// <param name="blogId">Page ID of the articles container</param>
        /// <param name="username">A valid EPiServer username</param>
        /// <param name="password">Password for the EPiServer user</param>
        /// <returns></returns>
        [XmlRpcMethod("wp.getAuthors")]
        public virtual AuthorData[] GetAuthors(string blogId, string username, string password)
        {
            Impersonate(username, password);

            ValidateBlogId(blogId);

            try
            {
                return GetAuthors(int.Parse(blogId));
            }
            catch (Exception exception)
            {
                throw new XmlRpcFaultException(400, "Unable to retrieve authors list: " + exception.Message);
            }
        }

        /// <summary>
        /// News the media object.
        /// </summary>
        /// <param name="blogId">Page ID of the articles container</param>
        /// <param name="username">A valid EPiServer username</param>
        /// <param name="password">Password for the EPiServer user</param>
        /// <param name="file">The file.</param>
        /// <returns></returns>
        [XmlRpcMethod("metaWeblog.newMediaObject")]
        public virtual UrlData NewMediaObject(object blogId, string username, string password, FileData file)
        {
            Impersonate(username, password);

            ValidateBlogId((string)blogId);

            try
            {
                var parentFolder = HostingEnvironment.VirtualPathProvider.GetDirectory("~/Global/") as UnifiedDirectory;

                if (parentFolder==null)
                {
                    throw new TemplateFoundationException("Unable to retrieve the 'Global Files' VPP folder");
                }

                // Create subfolder for 'MetaWeblog' and another subfolder for the current year -> /MetaWeblog/YYYY/
                var metaWeblogContainer =
                    HostingEnvironment.VirtualPathProvider.GetDirectory(string.Concat(parentFolder.VirtualPath, "MetaWeblog")) as UnifiedDirectory ??
                    parentFolder.CreateSubdirectory("MetaWeblog");

                var yearContainer =
                    HostingEnvironment.VirtualPathProvider.GetDirectory(string.Concat(metaWeblogContainer.VirtualPath, DateTime.Now.Year))
                    as UnifiedDirectory ??
                    metaWeblogContainer.CreateSubdirectory(DateTime.Now.Year.ToString());

                // Remove Live Writer-specific part of path
                var fileName = file.name.Replace("WindowsLiveWriter/", string.Empty);

                // Ignore folder path, but keep folder name in the file name
                fileName = fileName.Replace("/", "-");

                var newFile = yearContainer.CreateFile(fileName);

                var fileStream = new MemoryStream(file.bits);

                using (var reader = new BinaryReader(fileStream))
                {
                    using (var writer = new BinaryWriter(newFile.Open(FileMode.Create)))
                    {
                        while (reader.BaseStream.Position < reader.BaseStream.Length)
                        {
                            writer.Write(reader.ReadByte());
                        }
                    }
                }

                fileStream.Close();
                fileStream.Dispose();

                return new UrlData { url = newFile.VirtualPath };
            }
            catch
            {
                throw new XmlRpcFaultException(400, "Unable to upload file");
            }
        }

        /// <summary>
        /// Creates a new page based on the site's standard page type
        /// </summary>
        /// <param name="blogId">The page ID of the news container</param>
        /// <param name="username">Username of the account used to publish the page</param>
        /// <param name="password">Password for the account used to publish the page</param>
        /// <param name="content">The entire content of the page to publish</param>
        /// <param name="publish">Whether or not the page should be published or just saved in EPiServer</param>
        /// <returns></returns>
        [XmlRpcMethod("wp.newPage")]
        public virtual string NewPage(string blogId, string username, string password, PageObjectData content, bool publish)
        {
            try
            {
                Impersonate(username, password);

                ValidateBlogId(blogId);

                var standardPageTypeId = Settings.Instance.StandardPageTypeId;

                if (!standardPageTypeId.HasValue)
                {
                    throw new TemplateFoundationException("No standard page type specified, unable to create a new page");
                }

                // Create new page based on the standard page type
                var page = PageTypeResolver.Instance.ConvertToTyped(
                                DataFactory.Instance.GetDefaultPageData(
                                    new PageReference(int.Parse((string)content.wp_page_parent_id)),
                                    standardPageTypeId.Value,
                                    MasterLanguage));

                if (page==null)
                {
                    throw new TemplateFoundationException("Unable to create a new page due to a page type conversion error");
                }

                if (!(page is IStandardPage))
                {
                    throw new TemplateFoundationException("The site's standard page type does not implement IStandardPage");
                }

                if (!string.IsNullOrEmpty(content.wp_author_id))
                {
                    // Verify a page type for contact persons has been specified
                    if (Settings.Instance.PersonPageTypeId.HasValue)
                    {
                        // Find contact person's page and set the ContactPerson property accordingly
                        var authors = PageFactory.Instance.GetPagesByType(Settings.Instance.PersonPageTypeId.Value, false);

                        var authorPageLink = PageReference.EmptyReference;

                        var authorId = int.Parse(content.wp_author_id);

                        foreach (var p in authors)
                        {
                            if (p.PageLink.ID == authorId)
                            {
                                authorPageLink = p.PageLink;
                                break;
                            }
                        }

                        ((IStandardPage)page).PageContact = authorPageLink;
                    }
                    else
                    {
                        ((IStandardPage)page).PageContact = PageReference.EmptyReference;
                    }
                }

                page.PageName = HttpUtility.HtmlDecode(content.title);

                ((IStandardPage)page).Author = content.wp_author_display_name;
                ((IStandardPage)page).Description = content.mt_excerpt;
                ((IStandardPage)page).MainBody = content.description;               
                ((IStandardPage)page).Keywords = content.mt_keywords;

                if (page is IEnableComments)
                {
                    ((IEnableComments)page).EnableComments = content.mt_allow_comments == 1;
                }

                if (content.categories!=null)
                {
                    foreach (var category in content.categories)
                    {
                        ((IStandardPage)page).Tags.Add(new Tag(category));
                    }
                }

                if (!string.IsNullOrEmpty(content.wp_slug))
                {
                    page.URLSegment = HttpUtility.UrlEncode(content.wp_slug);
                }
                else
                {
                    page.URLSegment = UrlSegment.CreateUrlSegment(page);
                }

                if (content.dateCreated>new DateTime(1753, 1, 1))
                {
                    page.StartPublish = content.dateCreated;
                }

                DataFactory.Instance.Save(
                    page,
                    publish ? SaveAction.Publish : SaveAction.Save);

                return page.PageLink.ID.ToString();
            }
            catch
            {
                throw new XmlRpcFaultException(400, "Unable to create new page");
            }
        }

        /// <summary>
        /// Creates a new post
        /// </summary>
        /// <param name="blogId">Page ID of the articles container</param>
        /// <param name="username">A valid EPiServer username</param>
        /// <param name="password">Password for the EPiServer user</param>
        /// <param name="content">Main body content for a page or post</param>
        /// <param name="publish">Whether to publish the page or post, or if it should simply be saved</param>
        /// <returns></returns>
        [XmlRpcMethod("metaWeblog.newPost")]
        public string NewPost(string blogId, string username, string password, ContentData content, bool publish)
        {
            try
            {
                Impersonate(username, password);

                ValidateBlogId(blogId);

                if (!Settings.Instance.ArticlePageTypeId.HasValue)
                {
                    throw new TemplateFoundationException("No article page type specified, unable to create new post");
                }

                // Create new post
                var post = (PageTypeBase)DataFactory.Instance.GetDefaultPageData(
                    Settings.Instance.NewsContainer,
                    Settings.Instance.ArticlePageTypeId.Value,
                    MasterLanguage) as ArticlePageBase;

                if (post==null)
                {
                    throw new TemplateFoundationException("Unable to create a new post");
                }

                if (!string.IsNullOrEmpty(content.wp_author_id))
                {
                    // Verify a page type for contact persons has been specified
                    if (Settings.Instance.PersonPageTypeId.HasValue)
                    {
                        // Find contact person's page and set the ContactPerson property accordingly
                        var authors = PageFactory.Instance.GetPagesByType(Settings.Instance.PersonPageTypeId.Value, false);

                        var authorPageLink = PageReference.EmptyReference;

                        var authorId = int.Parse(content.wp_author_id);

                        foreach (var page in authors)
                        {
                            if (page.PageLink.ID == authorId)
                            {
                                authorPageLink = page.PageLink;
                                break;
                            }
                        }

                        post.PageContact = authorPageLink;
                    }
                    else
                    {
                        post.PageContact = PageReference.EmptyReference;
                    }
                }

                // Set content properties
                post.PageName = HttpUtility.HtmlDecode(content.title);
                post.Description = content.mt_excerpt;
                post.MainBody = content.description;
                post.Keywords = content.mt_keywords;
                post.EnableComments = content.mt_allow_comments == 1;

                // Set or generate slug (URL segment)
                if (!string.IsNullOrEmpty(content.wp_slug))
                {
                    post.URLSegment = HttpUtility.UrlEncode(content.wp_slug);
                }
                else
                {
                    post.URLSegment = UrlSegment.CreateUrlSegment(post);
                }

                // Set publish date
                if (content.dateCreated>new DateTime(1753, 1, 1))
                {
                    post.StartPublish = content.dateCreated;
                }

                // Add tags
                if (!PageReference.IsNullOrEmpty(Settings.Instance.TagsContainer))
                {
                    var tags = new TagCollection();
                    foreach (string tag in content.categories)
                    {
                        tags.Add(new Tag(tag));
                    }
                    post.Tags = tags;
                }

                DataFactory.Instance.Save(
                    post,
                    publish ? SaveAction.Publish : SaveAction.Save);

                return post.PageLink.ID.ToString();
            }
            catch
            {
                throw new XmlRpcFaultException(400, "Unable to create new post");
            }
        }

        /// <summary>
        /// Get categories.
        /// </summary>
        /// <param name="blogId">Page ID of the articles container</param>
        /// <param name="username">A valid EPiServer username</param>
        /// <param name="password">Password for the EPiServer user</param>
        /// <returns></returns>
        [XmlRpcMethod("wp.getCategories")]
        public virtual CategoryData[] WpGetCategories(string blogId, string username, string password)
        {
            // TODO Return categories
            throw new NotImplementedException();
        }

        /// <summary>
        /// Validates the page ID of the root container
        /// </summary>
        /// <param name="blogId">Page ID of the articles container</param>
        protected virtual void ValidateBlogId(string blogId)
        {
            // Verify blog ID
            if (!blogId.Equals(Settings.Instance.NewsContainer.ID.ToString(), StringComparison.OrdinalIgnoreCase))
            {
                throw new TemplateFoundationException("Specified blog ID does not match news container ID");
            }
        }

        /// <summary>
        /// Gets the current page ID.
        /// </summary>
        /// <value>The current page ID.</value>
        public string CurrentPageID
        {
            get
            {
                return HttpContext.Current.Request.QueryString["pageid"];
            }
        }

        /// <summary>
        /// Gets the master language.
        /// </summary>
        /// <value>The master language.</value>
        public ILanguageSelector MasterLanguage
        {
            get
            {
                return new LanguageSelector(MasterLanguageBranch);
            }
        }

        /// <summary>
        /// Gets the master language branch.
        /// </summary>
        /// <value>The master language branch.</value>
        public string MasterLanguageBranch
        {
            get
            {
                return PageFactory.Instance.GetStartPage().MetaWeblogPublishLanguage;
            }
        }
    }


}
